package com.espirit.eap.manager.workflow;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.GenericGenerator;

import com.espirit.EntityMapping;
import com.espirit.common.VersionAware;
import com.espirit.eap.sa.User;
import com.googlecode.cswish.model.Saas;
import com.googlecode.cswish.util.ClassUtil;

@Entity
@BatchSize(size=10)
public class WFInstance extends EntityMapping implements Serializable,VersionAware, Saas {

	private static final long serialVersionUID = -2148445703375276194L;

	private WFTemplate wfTemplate;
	private WFPhase wfPhase;
	private WFStatus status;
	private String description;
	private WFInstance prevInstance;
	private List<WFInstanceTracker> instanceTrackers;
	
	private String srcClassName;
	private String srcId;
	
	private Integer sid;
	public Integer getSid() {
		return sid;
	}

	public void setSid(Integer sid) {
		this.sid = sid;
	}
	
	@ManyToOne(targetEntity=WFTemplate.class,fetch=FetchType.LAZY)
	public WFTemplate getWfTemplate() {
		return wfTemplate;
	}
	public void setWfTemplate(WFTemplate wfTemplate) {
		this.wfTemplate = wfTemplate;
	}
	@ManyToOne(targetEntity=WFPhase.class,fetch=FetchType.LAZY)
	public WFPhase getWfPhase() {
		return wfPhase;
	}
	
	public void setWfPhase(WFPhase wfPhase) {
		this.wfPhase = wfPhase;
	}
	
//	@ManyToOne(targetEntity=Event.class,cascade=CascadeType.ALL,fetch=FetchType.LAZY)
//	public Event getEvent() {
//		return event;
//	}
//	
//	public void setEvent(Event event) {
//		this.event = event;
//	}
	@ManyToOne(targetEntity=WFStatus.class,fetch=FetchType.LAZY)
	public WFStatus getStatus() {
		return status;
	}
	public void setStatus(WFStatus status) {
		this.status = status;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
//	public void setMessage(Message message) {
//		this.message = message;
//	}
//	@ManyToOne(targetEntity=Message.class,cascade=CascadeType.ALL,fetch=FetchType.LAZY)
//	public Message getMessage() {
//		return message;
//	}
	public void setPrevInstance(WFInstance prevInstance) {
		this.prevInstance = prevInstance;
	}
	
	@ManyToOne(targetEntity=WFInstance.class,fetch=FetchType.LAZY)
	public WFInstance getPrevInstance() {
		return prevInstance;
	}
	
	private Date createdOn;
	private User created;
	
	public Date getCreatedOn() {
		return createdOn;
	}
	public void setCreatedOn(Date createdOn) {
		this.createdOn = createdOn;
	}
	@ManyToOne(targetEntity = User.class,fetch=FetchType.LAZY)
	public User getCreated() {
		return created;
	}
	public void setCreated(User created) {
		this.created = created;
	}
	
	@Transient
	public User getInitInstanceUser() {
		WFInstance currentInstance = this;
		WFInstance prevInstance = currentInstance.getPrevInstance();
		while (prevInstance != null){
			currentInstance = prevInstance;
			prevInstance = currentInstance.getPrevInstance();
		}
		return currentInstance.getCreated();
	}
	
	@Transient
	public List<User> getAllJoinedUsers(){
		List<User> users = new ArrayList<User>();
		users.add(this.getCreated());
		WFInstance currentInstance = this;
		WFInstance prevInstance = currentInstance.getPrevInstance();
		while (prevInstance != null){
			currentInstance = prevInstance;
			users.add(currentInstance.getCreated());
			prevInstance = currentInstance.getPrevInstance();
		}
		return users;
	}
	
	
	
//	private Event initedEvent;
//	@Transient
//	public Event getInitedEvent(){
//		if (initedEvent == null){
//			initedEvent = (Event) HibernateUtil.unproxy(getEvent());
//		}
//		return initedEvent;
//	}
	@OneToMany(targetEntity = WFInstanceTracker.class ,orphanRemoval = true, fetch=FetchType.LAZY,  cascade = CascadeType.ALL, mappedBy = "parent")
	public List<WFInstanceTracker> getInstanceTrackers() {
		return instanceTrackers;
	}
	public void setInstanceTrackers(List<WFInstanceTracker> instanceTrackers) {
		this.instanceTrackers = instanceTrackers;
	}
	
	public List<WFInstanceTracker> safeInstanceTrackers(){
		if (instanceTrackers == null){
			instanceTrackers = new ArrayList<WFInstanceTracker>();
		}
		return instanceTrackers;
	}
	public String getSrcId() {
		return srcId;
	}
	public void setSrcId(String srcId) {
		this.srcId = srcId;
	}
	public String getSrcClassName() {
		return srcClassName;
	}
	public void setSrcClassName(String srcClassName) {
		this.srcClassName = srcClassName;
	}
	
	@Transient
	public int getAcceptedUsers(){
		if (this.instanceTrackers == null) return 0;
		int count = 0;
		for(WFInstanceTracker tracker : this.instanceTrackers){
			if (tracker.getStatus() != null && tracker.getStatus().isAccept()){
				count ++;
			}
		}
		return count;
	}
	
	public void onSetSrcClassName(WorkflowAware workflowAware){
		this.setSrcClassName(ClassUtil.getClassName(workflowAware));
	}
}
